#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>

#define MSG_EXCEPT      020000  /* recv any msg except of specified type.*/ 


struct my_msg_st {
	long int my_msg_type;
	char some_text[BUFSIZ];
};
//从函数原型中猜测功能的实现？
int main()
{
	int running = 1;
	int msgid;
	struct my_msg_st some_data;
//	long int msg_to_receive = 1;//将原来的0改为1，为什么没有效果呢？
	long int msg_to_receive = 0;//将原来的0改为1，为什么没有效果呢？

	msgid = msgget((key_t) 1234, 0666| IPC_CREAT);//创建或访问一个消息队列

	/*
	 * 函数原型：int msgget(key_t key,int msgflg);
		 * 参数key，是由ftok函数获得，msgflg参数是一些标志位。
		 * 返回一个与键值key对应的消息队列描述字
	 * 在以下情况下，该调用将创建一个新的消息队列：
		 * 如果没有消息队列与键值key相对应，并且msgflg中包含了IPC_CREAT标志位
		 * key参数为IPC_PRIVATE，当key设置为常数IPC_PRIVATE并不意味这其它进程不能访问该消息队列，只意味着即将创建新的消息队列。
	 * 调用返回：成功返回消息队列描述字，否则返回-1
	 *
	 * */
	if (msgid == -1 ) {
		fprintf(stderr,"msgget failed with errno: [%d]\n", errno);
		exit (EXIT_FAILURE);
	}

	printf ("go loop..\n");
	while (running) {
		if (msgrcv(msgid, (void*) &some_data, 
//				BUFSIZ,msg_to_receive,MSG_EXCEPT | IPC_NOWAIT) == -1) {
				BUFSIZ,msg_to_receive,0) == -1) {
			fprintf (stderr, "msgrcv failed with errno:[%d]\n",errno);
			perror("msgrcv");
			exit(EXIT_FAILURE);
		}//从一个消息队列中获取消息
		/*
		 * msgrcv函数从一个消息队列中获取消息
		 * 函数原型：int msgrcv(int msgid,void * msg_ptr,size_t msg_se,long int msgtype,int msgfig);
			 * msgid是msgget函数返回的消息队列描述字
			 * msg_ptr是一个指向准备接收消息的指针，该指针的类型需定义如下：
				 * struct message{
				 *	long int msg_type;
				 *	// [....] 其它数据结构。数组，结构体等等。
				 * };
			 * msg_sz是msg_ptr指向的消息的长度，它不包括long int 消息类型成员变量的长度。
			 * msgtype是一个long int，它可以实习那一种简单形式的接收优先级。如果msgtype的值为0，就获取队列中的第一个可用消息。如果它的值大于0，就获取具有相同数据类型的第一个消息。如果它的值小于0就获取消息类型等于或小于msgtype的绝对值的第一个消息。
				 * 即，如果想按照消息发送的顺序来接收它们，就把msgtype设置wie0，如果只想获取某一特定类型的消息，就把此值设置为对应的类型值。
		 * */
		printf("You wrote: %s",some_data.some_text);
		if (strncmp(some_data.some_text, "end" ,3) == 0) {
			running = 0;
		}

	}

	if (msgctl(msgid, IPC_RMID,0) == -1) {
		fprintf(stderr, "msgctl(IPC_RMID) failed\n");
		exit (EXIT_FAILURE);
	}//删除这个消息队列，假如某个进程正在msgsnd或msgrcv函数中等待，这两个函数将失败。

	exit(EXIT_SUCCESS);
}
